home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 98
/
Skunkware 98.iso
/
src
/
mail
/
pine3.96.tar.gz
/
pine3.96.tar
/
pine3.96
/
pico
/
os_os2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-05-30
|
32KB
|
1,597 lines
/*
* $Id: os_os2.c,v 4.8 1996/05/31 00:08:47 mikes Exp $
*
* Program: Operating system dependent routines - OS/2 Text mode
*
*
* Michael Seibel
* Networks and Distributed Computing
* Computing and Communications
* University of Washington
* Administration Builiding, AG-44
* Seattle, Washington, 98195, USA
* Internet: mikes@cac.washington.edu
*
* Please address all bugs and comments to "pine-bugs@cac.washington.edu"
*
*
* Pine and Pico are registered trademarks of the University of Washington.
* No commercial use of these trademarks may be made without prior written
* permission of the University of Washington.
*
* Pine, Pico, and Pilot software and its included text are Copyright
* 1989-1996 by the University of Washington.
*
* The full text of our legal notices is contained in the file called
* CPYRIGHT, included with this distribution.
*
*
* Notes:
* - mouse support added (mss, 921215)
*
* Portions of this code derived from MicroEMACS 3.10:
*
* OS2.C: Operating specific I/O and Spawning functions
* under the OS/2 operating system
* for MicroEMACS 3.10
* (C)opyright 1988 by Daniel M. Lawrence
*
*/
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
#include <time.h>
#include <fcntl.h>
#include <io.h>
#include <process.h>
#include "osdep.h"
#include "estruct.h"
#include "pico.h"
#include "edef.h"
/*
* Internal functions...
*/
int checkmouse();
void invert_label(int, MENUITEM *);
int enhanced_keybrd(void);
int dont_interrupt(void);
int interrupt_ok(void);
int kbseq(int *);
int specialkey(unsigned int);
void do_alarm_signal(void);
void do_hup_signal(int sig);
char *pfnexpand(char *, int);
int ssleep(long);
void mouseon();
void mouseoff();
void turnmouseoff();
/*
* Useful global def's
*/
int timeout =0;
static int oldbut; /* Previous state of mouse buttons */
static int enhncd; /* Enhanced keyboard */
static KBDINFO initialKbdInfo;
#ifdef MOUSE
/*
* Useful definitions...
*/
static int mexist = 0; /* is the mouse driver installed? */
static int nbuttons; /* number of buttons on the mouse */
static unsigned mnoop;
static unsigned char okinfname[32] = {
0, 0, /* ^@ - ^G, ^H - ^O */
0, 0, /* ^P - ^W, ^X - ^_ */
0, 0x17, /* SP - ' , ( - / */
0xff, 0xe4, /* 0 - 7 , 8 - ? */
0x7f, 0xff, /* @ - G , H - O */
0xff, 0xe9, /* P - W , X - _ */
0x7f, 0xff, /* ` - g , h - o */
0xff, 0xf6, /* p - w , x - DEL */
0, 0, /* > DEL */
0, 0, /* > DEL */
0, 0, /* > DEL */
0, 0, /* > DEL */
0, 0 /* > DEL */
};
#endif
static void set_kbd(int state)
{
KBDINFO kbdInfo = initialKbdInfo;
if (state)
{
kbdInfo.fsMask &= ~(0x0001|0x0008|0x0100); /* echo,cooked */
kbdInfo.fsMask |= (0x0002|0x0004|0x0100); /* noecho,raw,shift-rpt on */
}
KbdSetStatus(&kbdInfo, 0);
}
/*
* DISable ctrl-break interruption
*/
dont_interrupt()
{
signal (SIGINT, SIG_IGN);
signal (SIGBREAK, SIG_IGN);
set_kbd(1);
}
/*
* re-enable ctrl-break interruption
*/
interrupt_ok()
{
set_kbd(0);
signal (SIGINT, SIG_DFL);
signal (SIGBREAK, SIG_DFL);
}
/*
* return true if an enhanced keyboard is present
*/
enhanced_keybrd()
{
return(1);
}
/*
* This function is called once to set up the terminal device streams.
*/
ttopen()
{
initialKbdInfo.cb = sizeof(initialKbdInfo);
KbdGetStatus(&initialKbdInfo, 0);
dont_interrupt(); /* don't allow interrupt */
enhncd = enhanced_keybrd(); /* check for extra keys */
#if MOUSE
init_mouse();
#else /* !MOUSE */
mexist = 0;
#endif /* MOUSE */
return(1);
}
#ifdef MOUSE
HMOU Mouse_Handle =(HMOU)-1;
#ifdef FASTVIO
int mouse_state =0;
#endif
/*
* init_mouse - check for and initialize mouse driver...
*/
init_mouse()
{
if (Mouse_Handle==(HMOU)-1) {
int rc = MouOpen(NULL, &Mouse_Handle);
mexist=0;
if (rc)
return(FALSE);
mexist=1;
nbuttons=2;
MouFlushQue(Mouse_Handle);
turnmouseoff();
}
return(TRUE);
}
static int mouchk()
{
if (mexist)
return (Mouse_Handle==(HMOU)-1) ? init_mouse() : TRUE;
return FALSE;
}
deinit_mouse()
{
turnmouseoff();
}
/*
* mouseon - call made available for programs calling pico to turn ON the
* mouse cursor.
*/
void
mouseon()
{
/* Show Cursor */
if (mouchk() && !mouse_state) {
#ifdef FASTVIO
mouse_state=TRUE;
vidUpdate();
#else
MouDrawPtr(Mouse_Handle);
#endif
}
}
void
turnmouseoff()
{
static NOPTRRECT r = { 0, 0, (USHORT)-1, (USHORT)-1 };
if (r.cRow == (USHORT)-1) {
VIOMODEINFO mi;
mi.cb = sizeof mi;
VioGetMode(&mi, 0);
r.cRow = mi.row-1;
r.cCol = mi.col-1;
}
/* Hide Cursor */
MouRemovePtr(&r, Mouse_Handle);
mouse_state=FALSE;
}
/*
* mouseon - call made available for programs calling pico to turn OFF the
* mouse cursor.
*/
void
mouseoff()
{
#ifdef FASTVIO
/* This is ignored if in FASTVIO mode */
#else
if (mouchk()) {
turnmouseoff();
}
#endif
}
#endif
/*
* This function gets called just before we go back home to the command
* interpreter.
*/
ttclose()
{
if(!Pmaster)
interrupt_ok();
#ifdef MOUSE
deinit_mouse();
#endif
return(1);
}
/*
* Flush terminal buffer. Does real work where the terminal output is buffered
* up. A no-operation on systems where byte at a time terminal I/O is done.
*/
ttflush()
{
return(1);
}
/*
* specialkey - return special key definition
*/
specialkey(kc)
unsigned kc;
{
switch(kc){
case 0x3b00 : return(F1);
case 0x3c00 : return(F2);
case 0x3d00 : return(F3);
case 0x3e00 : return(F4);
case 0x3f00 : return(F5);
case 0x4000 : return(F6);
case 0x4100 : return(F7);
case 0x4200 : return(F8);
case 0x4300 : return(F9);
case 0x4400 : return(F10);
case 0x8500 : return(F11);
case 0x8600 : return(F12);
case 0x4800 : return(K_PAD_UP);
case 0x5000 : return(K_PAD_DOWN);
case 0x4b00 : return(K_PAD_LEFT);
case 0x4d00 : return(K_PAD_RIGHT);
case 0x4700 : return(K_PAD_HOME);
case 0x4f00 : return(K_PAD_END);
case 0x4900 : return(K_PAD_PREVPAGE);
case 0x5100 : return(K_PAD_NEXTPAGE);
case 0x5300 : return(K_PAD_DELETE);
case 0x48e0 : return(K_PAD_UP); /* grey key version */
case 0x50e0 : return(K_PAD_DOWN); /* grey key version */
case 0x4be0 : return(K_PAD_LEFT); /* grey key version */
case 0x4de0 : return(K_PAD_RIGHT); /* grey key version */
case 0x47e0 : return(K_PAD_HOME); /* grey key version */
case 0x4fe0 : return(K_PAD_END); /* grey key version */
case 0x49e0 : return(K_PAD_PREVPAGE); /* grey key version */
case 0x51e0 : return(K_PAD_NEXTPAGE); /* grey key version */
case 0x53e0 : return(K_PAD_DELETE); /* grey key version */
default : return(NODATA);
}
}
/*
* Read a character from the terminal, performing no editing and doing no echo
* at all. Also mouse events are forced into the input stream here.
*/
ttgetc()
{
int key = kbd_getkey();
return key ? key : NODATA;
}
/*
* ctrlkey - used to check if the key hit was a control key.
*/
ctrlkey()
{
return !!(kbd_shift() & KBDSTF_CONTROL);
}
/*
* win_multiplex - give OS/2 a shot at the CPU
*/
win_multiplex()
{
DosSleep(32);
}
/*
* Read in a key.
* Do the standard keyboard preprocessing. Convert the keys to the internal
* character set. Resolves escape sequences and returns no-op if global
* timeout value exceeded.
*/
GetKey()
{
unsigned ch = 0, lch, intrupt = 0;
long timein;
vidUpdate();
if(mexist || timeout) {
timein = time(0L);
#ifdef MOUSE
mouseon(); /* Show Cursor */
#endif
while(!kbd_ready()) {
#if MOUSE
if(timeout && time(0L) >= timein+timeout){
mouseoff(); /* Hide Cursor */
return(NODATA);
}
if(checkmouse(&ch,0,0,0)){ /* something happen ?? */
mouseoff(); /* Hide Cursor */
curwp->w_flag |= WFHARD;
return(ch);
}
#else
if(time(0L) >= timein+timeout) {
mouseoff(); /* Hide Cursor */
return(NODATA);
}
#endif /* MOUSE */
/*
* Surrender the CPU...
*/
win_multiplex();
}
#ifdef MOUSE
mouseoff(); /* Hide Cursor */
#endif /* MOUSE */
}
ch = (*term.t_getchar)();
lch = (ch&0xff);
return((lch && (lch != 0xe0 || !(ch & 0xff00)))
? (lch < ' ') ? (CTRL|(lch + '@'))
: (lch == ' ' && ctrlkey()) ? (CTRL|'@') : lch
: specialkey(ch));
}
#if MOUSE
/*
* checkmouse - look for mouse events in key menu and return
* appropriate value.
*/
int
checkmouse(ch, down, xxx, yyy)
unsigned *ch;
int down, xxx, yyy;
{
MOUQUEINFO qi;
if(!mouchk())
return(FALSE);
if (MouGetNumQueEl(&qi, Mouse_Handle)==0 && qi.cEvents)
{
MOUEVENTINFO m;
USHORT w = MOU_NOWAIT;
/* check to see if any mouse buttons are different */
if (MouReadEventQue(&m, &w, Mouse_Handle)==0)
{
int k;
int rv = 0;
int button = M_BUTTON_LEFT;
int newbut = ((m.fs & 4)?1:0) | ((m.fs & 16)?2:0) | ((m.fs & 64)?4:0);
/* only notice button changes */
if (oldbut == newbut)
return(FALSE);
for (k=1; k != (1 << nbuttons); k <<= 1) {
/* For each button on the mouse */
if ((oldbut&k) != (newbut&k)) {
if(k == 1){
static int oindex;
int i = 0;
MENUITEM *mp;
if(newbut&k) /* button down */
oindex = -1;
for(mp = mfunc; mp; mp = mp->next)
if(mp->action && M_ACTIVE(m.row, m.col, mp))
break;
if(mp){
unsigned long r;
r = (*mp->action)((newbut&k) ? M_EVENT_DOWN : M_EVENT_UP,
m.row, m.col, button, 0);
if(r & 0xffff){
*ch = (unsigned)((r>>16)&0xffff);
rv = TRUE;
}
}
else{
while(1){ /* see if we understand event */
if(i >= 12){
i = -1;
break;
}
if(M_ACTIVE(m.row, m.col, &menuitems[i]))
break;
i++;
}
if(newbut&k){ /* button down */
oindex = i; /* remember where */
if(i != -1) { /* invert label */
invert_label(1, &menuitems[i]);
}
}
else{ /* button up */
if(oindex != -1){
if(i == oindex){
*ch = menuitems[i].val;
rv = 1;
}
}
}
}
if(!(newbut&k) && oindex != -1) {
invert_label(0, &menuitems[oindex]); /* restore label */
}
}
oldbut = newbut;
return(rv);
}
++button;
}
}
}
return(FALSE);
}
/*
* invert_label - highlight the label of the given menu item.
*/
void
invert_label(state, m)
int state;
MENUITEM *m;
{
USHORT r, c;
VIOCURSORINFO oldInfo, newInfo;
int i, j, p;
char *lp;
int old_state = getrevstate();
if(m->val == mnoop)
return;
VioGetCurPos(&r, &c, 0);
VioGetCurType(&oldInfo, 0);
newInfo = oldInfo;
newInfo.attr = (USHORT)-1;
VioSetCurType(&newInfo, 0); /* Hide Cursor */
(*term.t_move)(m->tl.r, m->tl.c);
(*term.t_rev)(state);
for(i = m->tl.r; i <= m->br.r; i++)
for(j = m->tl.c; j <= m->br.c; j++)
if(i == m->lbl.r && j == m->lbl.c){ /* show label?? */
lp = m->label;
while(*lp && j++ < m->br.c)
(*term.t_putchar)(*lp++);
continue;
}
else (*term.t_putchar)(' ');
(*term.t_rev)(old_state);
VioSetCurPos(r, c, 0); /* restore old position */
VioSetCurType(&oldInfo, 0); /* Show Cursor */
vidUpdate();
}
#endif /* MOUSE */
/*
* alt_editor - fork off an alternate editor for mail message composition
*/
#define MAXARGS 10
alt_editor(f, n)
{
char *fn; /* tmp holder for file name */
char *cp;
char *writetmp();
int child, rc, i, done = 0;
long l;
int stat;
FILE *p;
char *args[MAXARGS]; /* ptrs into edit command */
char eb[NLINE];
if(Pmaster == NULL)
return(-1);
if(gmode&MDSCUR){
emlwrite("Alternate editor not available in restricted mode", NULL);
return(-1);
}
if(Pmaster->alt_ed == NULL){
if (!(gmode&MDADVN)) {
emlwrite("\007Unknown Command",NULL);
return(-1);
}
if((cp=getenv("VISUAL"))!=0 || (cp=getenv("EDITOR"))!=0)
strcpy(eb, (char *)getenv("EDITOR"));
else *eb = '\0';
while(!done) {
rc = mlreplyd("Which alternate editor ? ",eb,NLINE,QDEFLT,NULL);
switch(rc) {
case ABORT:
return(-1);
case HELPCH:
emlwrite("no alternate editor help yet", NULL);
/* take sleep and break out after there's help */
sleep(3);
break;
case (CTRL|'L'):
sgarbf = TRUE;
update();
break;
case TRUE:
case FALSE: /* does editor exist ? */
if(*eb == '\0'){ /* leave silently? */
mlerase();
return(-1);
}
done++;
break;
default:
break;
}
}
}
else
strcpy(eb, Pmaster->alt_ed);
if((fn=writetmp(0, 1)) == NULL){ /* get temp file */
emlwrite("Problem writing temp file for alt editor", NULL);
return(-1);
}
strcat(eb, " ");
strcat(eb, fn);
cp = eb;
for(i=0; *cp != '\0';i++) { /* build args array */
if(i < MAXARGS) {
args[i] = NULL; /* in case we break out */
}
else{
emlwrite("Too many args for command!", NULL);
return(-1);
}
while(isspace((unsigned char)(*cp)))
if(*cp != '\0')
cp++;
else break;
args[i] = cp;
while(!isspace((unsigned char)(*cp)))
if(*cp != '\0')
cp++;
else
break;
if(*cp != '\0')
*cp++ = '\0';
}
args[i] = NULL;
(*Pmaster->raw_io)(0); /* turn OFF raw mode */
emlwrite("Invoking alternate editor...", NULL);
{
void (*ohup)() = signal(SIGHUP, SIG_IGN); /* ignore signals for now */
void (*oint)() = signal(SIGINT, SIG_IGN);
cp=args[0];
rc = spawnvp(P_WAIT, cp, args);
signal(SIGHUP, ohup); /* restore signals */
signal(SIGINT, oint);
}
(*Pmaster->raw_io)(1); /* turn ON raw mode */
dont_interrupt();
if (rc==-1) { /* Can't run it */
emlwrite("error attempting to run alt editor", NULL);
}
/*
* replace edited text with new text
*/
else{
rc = 0;
curbp->b_flag &= ~BFCHG; /* make sure old text gets blasted */
readin(fn, 0); /* read new text overwriting old */
curbp->b_flag |= BFCHG; /* mark dirty for packbuf() */
}
unlink(fn); /* blast temp file */
ttopen(); /* reset the signals */
refresh(0, 1); /* redraw */
return(rc);
}
/*
* bktoshell - suspend and wait to be woken up
*/
bktoshell() /* suspend MicroEMACS and wait to wake up */
{
int i;
static char * shell = NULL;
if (shell == NULL) {
char *p;
shell=getenv("SHELL");
if (!shell && !(shell=getenv("COMSPEC")))
shell="CMD.EXE";
if ((p = strdup(shell)) > 0) {
for (shell = p; (p = strchr(shell, '/')) != 0; )
*p = '\\';
}
}
(*term.t_move)(term.t_nrow, 0);
(*term.t_eeol)();
exit_text_mode(NULL);
interrupt_ok();
if (system(shell) == -1)
emlwrite("Error loading %s", shell);
else refresh(0, 1); /* redraw */
enter_text_mode(NULL);
dont_interrupt();
}
/*
* P_open - run the given command in a sub-shell returning a file pointer
* from which to read the output
*
* note:
* For OS's other than unix, you will have to rewrite this function.
* Hopefully it'll be easy to exec the command into a temporary file,
* and return a file pointer to that opened file or something.
*/
FILE *P_open(c)
char *c;
{
return(popen(c,"r"));
}
/*
* P_close - close the given descriptor
*
*/
P_close(fp)
FILE *fp;
{
return(pclose(fp));
}
/*
* A replacement for fflush
* relies on #define fflush os2_fflush
*/
#undef fflush
int
os2_fflush (FILE *f)
{
if (f == stdout) {
vidUpdate();
}
else
fflush (f);
}
/*
* ttresize - recompute the screen dimensions if necessary, and then
* adjust pico's internal buffers accordingly
*/
int
ttresize ()
{
return (0); /* no op */
}
/*
* picosigs - Install any handlers for the signals we're interested
* in catching.
*/
picosigs()
{
signal(SIGHUP, do_hup_signal); /* deal with SIGHUP */
signal(SIGTERM, do_hup_signal); /* deal with SIGTERM */
}
/*
* do_hup_signal - jump back in the stack to where we can handle this
*/
void
do_hup_signal(int sig)
{
sig=sig;
signal(SIGHUP, SIG_IGN); /* ignore further SIGHUP's */
signal(SIGTERM, SIG_IGN); /* ignore further SIGTERM's */
if(Pmaster){
extern jmp_buf finstate;
longjmp(finstate, COMP_GOTHUP);
}
else{
/*
* if we've been interrupted and the buffer is changed,
* save it...
*/
if(anycb() == TRUE){ /* time to save */
if(curbp->b_fname[0] == '\0'){ /* name it */
strcpy(curbp->b_fname, "pico.sav");
}
else{
strcat(curbp->b_fname, ".sav");
}
writeout(curbp->b_fname);
}
vttidy();
exit(1);
}
}
#ifdef MOUSE
/*
* end_mouse - a no-op on DOS/Windows
*/
void
end_mouse()
{
}
/*
* mouseexist - function to let outsiders know if mouse is turned on
* or not.
*/
mouseexist()
{
return(mexist);
}
#endif /* MOUSE */
/*
* fallowc - returns TRUE if c is allowable in filenames, FALSE otw
*/
fallowc(c)
int c;
{
return(okinfname[c>>3] & 0x80>>(c&7));
}
/*
* fexist - returns TRUE if the file exists, FALSE otherwise
*/
fexist(file, m, l)
char *file, *m;
long *l;
{
struct stat sbuf;
if(l != NULL)
*l = 0L;
if(stat(file, &sbuf) < 0){
if(ENOENT) /* File not found */
return(FIOFNF);
else
return(FIOERR);
}
if(l != NULL)
*l = sbuf.st_size;
if(sbuf.st_mode & S_IFDIR)
return(FIODIR);
if(m[0] == 'r') /* read access? */
return((S_IREAD & sbuf.st_mode) ? FIOSUC : FIONRD);
else if(m[0] == 'w') /* write access? */
return((S_IWRITE & sbuf.st_mode) ? FIOSUC : FIONWT);
else if(m[0] == 'x') /* execute access? */
return((S_IEXEC & sbuf.st_mode) ? FIOSUC : FIONEX);
return(FIOERR); /* what? */
}
/*
* isdir - returns true if fn is a readable directory, false otherwise
* silent on errors (we'll let someone else notice the problem;)).
*/
isdir(fn, l)
char *fn;
long *l;
{
struct stat sbuf;
if(l)
*l = 0;
if(stat(fn, &sbuf) < 0)
return(0);
if(l)
*l = sbuf.st_size;
return(sbuf.st_mode & S_IFDIR);
}
/*
* gethomedir - returns the users home directory
* Note: home is malloc'd for life of pico
*/
char *gethomedir(l)
int *l;
{
static char *home = NULL;
static short hlen = 0;
if(home == NULL){
char *p, buf[NLINE];
if (home=getenv("PINEHOME")) /* Overrides all others */
strcpy(buf, home);
else if (home=getenv("HOME")) /* Convenient group placement */
strcpy(buf, home);
else if (home=getenv("ETC")) /* IBM TCPIP */
strcpy(buf, home);
else sprintf(buf, "%c:\\", _getdrive());
hlen = strlen(buf);
if ((home=(char *)malloc(hlen + 1)) == NULL) {
emlwrite("Problem allocating space for home dir", NULL);
return(0);
}
strcpy(home, buf);
while ((p=strchr(home,'/')) != NULL) /* Normalise, just in case */
*p = '\\';
}
if(l)
*l = hlen;
return(home);
}
/*
* homeless - returns true if given file does not reside in the current
* user's home directory tree.
*/
homeless(f)
char *f;
{
char *home;
int len;
home = gethomedir(&len);
return(strncmp(home, f, len));
}
/*
* errstr - return system error string corresponding to given errno
* Note: strerror() is not provided on all systems, so it's
* done here once and for all.
*/
char *errstr(err)
int err;
{
return((err >= 0 && err < sys_nerr) ? (char*)sys_errlist[err] : NULL);
}
/*
* getfnames - return all file names in the given directory in a single
* malloc'd string. n contains the number of names
*/
char *getfnames(dn, pat, n, e)
char *dn, *pat, *e;
int *n;
{
int status;
long l;
char *names, *np, *p;
char buf[NLINE];
struct stat sbuf;
ULONG count=1;
FILEFINDBUF3 findbuf;
HDIR hdir=HDIR_CREATE;
*n = 0;
while ((p = strchr(dn, '/')) != NULL)
*p = '\\';
if(stat(dn, &sbuf) < 0){
if(e)
sprintf(e, "\007Dir \"%s\": %s", dn, strerror(errno));
return(NULL);
}
else{
l = sbuf.st_size;
if(!(sbuf.st_mode & S_IFDIR)){
if(e)
sprintf(e, "\007Not a directory: \"%s\"", dn);
return(NULL);
}
}
if((names=(char *)malloc(sizeof(char)*3072)) == NULL){
if(e)
sprintf(e, "\007Can't malloc space for file names", NULL);
return(NULL);
}
np = names;
strcpy(buf, dn);
if (*buf && buf[strlen(buf)-1] != '\\')
strcat(buf, "\\");
if (pat && *pat)
strcat(buf, pat);
if (!pat || !*pat || strchr(pat, '.')==NULL)
strcat(buf, "*");
if (DosFindFirst(buf, &hdir, FILE_NORMAL|FILE_DIRECTORY, &findbuf,
sizeof findbuf, &count, FIL_STANDARD) != 0) {
if(e)
sprintf(e, "Can't find first file in \"%s\"", dn);
free((char *) names);
return(NULL);
}
do{
(*n)++;
p = findbuf.achName;
while((*np++ = *p++) != '\0')
;
}
while(DosFindNext(hdir, &findbuf, sizeof findbuf, &count) == 0);
return(names);
}
/*
* fioperr - given the error number and file name, display error
*/
void
fioperr(e, f)
int e;
char *f;
{
switch(e){
case FIOFNF: /* File not found */
emlwrite("\007File \"%s\" not found", f);
break;
case FIOEOF: /* end of file */
emlwrite("\007End of file \"%s\" reached", f);
break;
case FIOLNG: /* name too long */
emlwrite("\007File name \"%s\" too long", f);
break;
case FIODIR: /* file is a directory */
emlwrite("\007File \"%s\" is a directory", f);
break;
case FIONWT:
emlwrite("\007Write permission denied: %s", f);
break;
case FIONRD:
emlwrite("\007Read permission denied: %s", f);
break;
case FIONEX:
emlwrite("\007Execute permission denied: %s", f);
break;
default:
emlwrite("\007File I/O error: %s", f);
}
}
/*
* pfnexpand - pico's function to expand the given file name if there is
* a leading '~'
*/
char *pfnexpand(fn, len)
char *fn;
int len;
{
register char *x, *y, *z;
char *home = gethomedir(NULL);
char name[20];
if(*fn == '~') {
for(x = fn+1, y = name; *x != '/' && *x != '\\' && *x != '\0'; *y++ = *x++);
*y = '\0';
if(strlen(home) + strlen(fn) > len) {
return(NULL);
}
/* make room for expanded path */
for(z=x+strlen(x),y=fn+strlen(x)+strlen(home);
z >= x;
*y-- = *z--);
/* and insert the expanded address */
for(x=fn,y=home; *y != '\0'; *x++ = *y++);
}
return(fn);
}
getcurdir(drv, buf)
int drv;
char *buf;
{
LONG ml = _MAX_PATH;
drv = drv ? toupper(drv) : _getdrive();
buf[0] = (char)drv;
buf[1] = ':';
buf[2] = '\\';
return DosQueryCurrentDir(drv-'A'+1, buf + 3, &ml) == 0;
}
/*
* fixpath - make the given pathname into an absolute path
*/
fixpath(name, len)
char *name;
int len;
{
char *p;
char file[_MAX_PATH];
int dr;
if(!len)
return(0);
/* normalize: xlate any '/' into '\\' */
while ((p=strchr(name,'/'))!=NULL)
*p='\\';
/* return the full path of given file */
if(isalpha((unsigned char)name[0]) && name[1] == ':'){ /* have drive spec? */
if(name[2] == '\\') /* including path? */
return 1;
if (!getcurdir(name[0], file))
return 0;
name += 2;
}
else if(name[0] == '.' && (!name[1] || name[1] == '\\')) {
getcurdir(0, file);
name += (1 + name[1] == '\\');
}
else if(name[0] == '\\') { /* no drive spec! */
file[0] = (char)_getdrive();
file[1] = ':';
file[2] = '\0';
}
else getcurdir(0, file); /* no qualification */
if(*name) { /* if name, append it */
p = NULL;
if (name[0] == '.' && name[1] == '.' && (!name[2] || name[2] == '\\')) {
if ((p = strrchr(name,'\\'))!=NULL) {
*p++ = '\0';
if (!*p && (p=strrchr(name,'\\'))!=NULL)
*p = '\0';
}
name += (2 & name[2] == '\\');
}
if (*name) {
if (name[0] == '.' && (!name[1] || name[1] == '\\'))
name += (1 + name[1] == '\\');
if (*name) {
if (*file && file[strlen(file)-1] != '\\' && *name != '\\')
strcat(file, "\\");
strcat(file, name);
}
}
}
strncpy(name, file, len); /* copy back to real buffer */
name[len-1] = '\0'; /* tie off just in case */
return(1);
}
/*
* compresspath - given a base path and an additional directory, collapse
* ".." and "." elements and return absolute path (appending
* base if necessary).
*
* returns 1 if OK,
* 0 if there's a problem
* new path, by side effect, if things went OK
*/
compresspath(base, path, len)
char *base, *path;
int len;
{
register int i;
int depth = 0;
char *p;
char *stack[32];
char pathbuf[NLINE];
#define PUSHD(X) (stack[depth++] = X)
#define POPD() ((depth > 0) ? stack[--depth] : "")
strcpy(pathbuf, path);
fixpath(pathbuf, len);
p = pathbuf;
for(i=0; pathbuf[i] != '\0'; i++){ /* pass thru path name */
if(pathbuf[i] == C_FILESEP){
if(p != pathbuf)
PUSHD(p); /* push dir entry */
p = &pathbuf[i+1]; /* advance p */
pathbuf[i] = '\0'; /* cap old p off */
continue;
}
if(pathbuf[i] == '.'){ /* special cases! */
if(pathbuf[i+1] == '.' /* parent */
&& (pathbuf[i+2] == C_FILESEP || pathbuf[i+2] == '\0')){
if(!strcmp(POPD(),"")) /* bad news! */
return(0);
i += 2;
p = (pathbuf[i] == '\0') ? "" : &pathbuf[i+1];
}
else if(pathbuf[i+1] == C_FILESEP || pathbuf[i+1] == '\0'){
i++;
p = (pathbuf[i] == '\0') ? "" : &pathbuf[i+1];
}
}
}
if(*p != '\0')
PUSHD(p); /* get last element */
path[0] = '\0';
for(i = 0; i < depth; i++){
strcat(path, S_FILESEP);
strcat(path, stack[i]);
}
return(1); /* everything's ok */
}
/*
* tmpname - return a temporary file name in the given buffer
*/
void
tmpname(name)
char *name;
{
static int counter = 0;
static char *tmpdir;
char * p;
if (!tmpdir && (tmpdir=getenv("TEMP"))==NULL && (tmpdir = getenv("TMP"))==NULL)
tmpdir=".";
p = strchr(strcpy(name, tmpdir), '/');
while (p != NULL)
{
*p++ = '\\';
p = strchr(p, '/');
}
p = strrchr(name, '\\');
if (p == 0)
p = name + strlen(name);
else if (*++p != 0)
{
p = name + strlen(name);
*p++ = '\\';
}
sprintf(p, "pn%d%d", getpid(), ++counter);
}
/*
* Take a file name, and from it
* fabricate a buffer name. This routine knows
* about the syntax of file names on the target system.
* I suppose that this information could be put in
* a better place than a line of code.
*/
void
makename(bname, fname)
char bname[];
char fname[];
{
register char *cp1;
register char *cp2;
cp1 = &fname[0];
while (*cp1 != 0)
++cp1;
while (cp1!=&fname[0] && cp1[-1]!='\\')
--cp1;
cp2 = &bname[0];
while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
*cp2++ = *cp1++;
*cp2 = 0;
}
/*
* copy - copy contents of file 'a' into a file named 'b'. Return error
* if either isn't accessible or is a directory
*/
copy(a, b)
char *a, *b;
{
int n, rv = 0;
struct stat tsb, fsb;
if(stat(a, &fsb) < 0){ /* get source file info */
emlwrite("Can't Copy: %s", errstr(errno));
return(-1);
}
if(!(fsb.st_mode&S_IREAD)){ /* can we read it? */
emlwrite("\007Read permission denied: %s", a);
return(-1);
}
if((fsb.st_mode&S_IFMT) == S_IFDIR){ /* is it a directory? */
emlwrite("\007Can't copy: %s is a directory", a);
return(-1);
}
if(stat(b, &tsb) < 0){ /* get dest file's mode */
switch(errno){
case ENOENT:
break; /* these are OK */
default:
emlwrite("\007Can't Copy: %s", errstr(errno));
return(-1);
}
}
else{
if(!(tsb.st_mode&S_IWRITE)){ /* can we write it? */
emlwrite("\007Write permission denied: %s", b);
return(-1);
}
if((tsb.st_mode&S_IFMT) == S_IFDIR){ /* is it directory? */
emlwrite("\007Can't copy: %s is a directory", b);
return(-1);
}
if(fsb.st_dev == tsb.st_dev && fsb.st_ino == tsb.st_ino){
emlwrite("\007Identical files. File not copied", NULL);
return(-1);
}
}
rv=DosCopy(a, b, DCPY_EXISTING);
if(rv != 0 < 0){
emlwrite("Copy Failed: DosCopy() error %d", rv);
return(-1);
}
return(rv);
}
/*
* Open a file for writing. Return TRUE if all is well, and FALSE on error
* (cannot create).
*/
ffwopen(fn)
char *fn;
{
extern FILE *ffp;
if ((ffp=fopen(fn, "w")) == NULL) {
emlwrite("Cannot open file for writing", NULL);
return (FIOERR);
}
return (FIOSUC);
}
/*
* Close a file. Should look at the status in all systems.
*/
ffclose()
{
extern FILE *ffp;
if (fclose(ffp) != FALSE) {
emlwrite("Error closing file", NULL);
return(FIOERR);
}
return(FIOSUC);
}
/*
* ffelbowroom - make sure the destination's got enough room to receive
* what we're about to write...
*/
ffelbowroom(fn)
char *fn;
{
return(TRUE);
}
/*
* worthit - generic sort of test to roughly gage usefulness of using
* optimized scrolling.
*
* note:
* returns the line on the screen, l, that the dot is currently on
*/
worthit(l)
int *l;
{
int i; /* l is current line */
unsigned below; /* below is avg # of ch/line under . */
*l = doton(&i, &below);
below = (i > 0) ? below/(unsigned)i : 0;
return(below > 3);
}
/*
* o_insert - optimize screen insert of char c
*/
o_insert(c)
char c;
{
return(0);
}
/*
* o_delete - optimized character deletion
*/
o_delete()
{
return(0);
}
/*
* pico_new_mail - just checks mtime and atime of mail file and notifies user
* if it's possible that they have new mail.
*/
pico_new_mail()
{
return(0);
}
/*
* time_to_check - checks the current time against the last time called
* and returns true if the elapsed time is > timeout
*/
time_to_check()
{
static time_t lasttime = 0L;
if(!timeout)
return(FALSE);
if(time((long *) 0) - lasttime > (time_t)timeout){
lasttime = time((long *) 0);
return(TRUE);
}
else
return(FALSE);
}
/*
* sstrcasecmp - compare two pointers to strings case independently
*/
sstrcasecmp(s1, s2)
QcompType *s1, *s2;
{
return(stricmp(*(char **)s1, *(char **)s2));
}
/*
* sleep the given number of microseconds
*/
ssleep(s)
clock_t s;
{
s += clock();
while(s > clock())
;
}
/*
* chkptinit -- initialize anything we need to support composer
* checkpointing
*/
chkptinit(file, n)
char *file;
int n;
{
if(!file[0]){
long gmode_save = gmode;
if(gmode&MDCURDIR)
gmode &= ~MDCURDIR; /* so fixpath will use home dir */
strcpy(file, "#picoTM0.txt");
fixpath(file, NLINE);
gmode = gmode_save;
}
else{
int l = strlen(file);
if(file[l-1] != '\\'){
file[l++] = '\\';
file[l] = '\0';
}
strcpy(file + l, "#picoTM0.txt");
}
if(fexist(file, "r", NULL) == FIOSUC){ /* does file exist? */
char copy[NLINE];
strcpy(copy, "#picoTM1.txt");
fixpath(copy, NLINE);
rename(file, copy); /* save so we don't overwrite it */
}
unlink(file);
}
static USHORT myShift = 0;
int kbd_ready()
{
KBDKEYINFO ki;
if (KbdPeek(&ki, 0)==0)
{
if (ki.fbStatus & 0x40) {
int key = (USHORT)((ki.chScan << 8) | ki.chChar);
myShift = ki.fsState;
if (!key && ki.fbStatus & 0x01) {
KbdCharIn(&ki, IO_WAIT, 0);
}
return key;
}
}
return 0;
}
int kbd_getkey()
{
KBDKEYINFO ki;
while (KbdCharIn(&ki, IO_WAIT, 0)==0) {
if (ki.fbStatus & 0x40) {
myShift = ki.fsState;
return (USHORT)((ki.chScan << 8) | ki.chChar);
}
if (ki.fbStatus & 0x01) {
myShift = ki.fsState;
}
}
return NODATA;
}
void kbd_flush()
{
KbdFlushBuffer(0);
}
int kbd_shift()
{
return myShift;
}